package org.unidata.mdm.meta.type.model;

import static org.unidata.mdm.meta.type.model.ModelNamespace.META_MODEL_NAMESPACE;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.unidata.mdm.core.type.model.ModelSource;
import org.unidata.mdm.core.type.model.source.AbstractModelSource;
import org.unidata.mdm.meta.configuration.TypeIds;
import org.unidata.mdm.meta.type.model.entities.EntitiesGroup;
import org.unidata.mdm.meta.type.model.entities.Entity;
import org.unidata.mdm.meta.type.model.entities.LookupEntity;
import org.unidata.mdm.meta.type.model.entities.NestedEntity;
import org.unidata.mdm.meta.type.model.entities.Relation;
import org.unidata.mdm.meta.util.ModelUtils;

import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;

@JacksonXmlRootElement(localName = "data", namespace = META_MODEL_NAMESPACE)
@JsonPropertyOrder({
    "lookups",
    "nesteds",
    "registers",
    "relations",
    "entitiesGroup"
})
public class DataModel extends AbstractModelSource<DataModel> implements ModelSource, Serializable {
    /**
     * GSVUID.
     */
    private static final long serialVersionUID = 915008605103597822L;

    @JacksonXmlElementWrapper(localName = "lookups", namespace = META_MODEL_NAMESPACE)
    @JacksonXmlProperty(localName = "lookup", namespace = META_MODEL_NAMESPACE)
    private List<LookupEntity> lookupEntities;

    @JacksonXmlElementWrapper(localName = "nesteds", namespace = META_MODEL_NAMESPACE)
    @JacksonXmlProperty(localName = "nested", namespace = META_MODEL_NAMESPACE)
    private List<NestedEntity> nestedEntities;

    @JacksonXmlElementWrapper(localName = "registers", namespace = META_MODEL_NAMESPACE)
    @JacksonXmlProperty(localName = "register", namespace = META_MODEL_NAMESPACE)
    private List<Entity> entities;

    @JacksonXmlElementWrapper(localName = "relations", namespace = META_MODEL_NAMESPACE)
    @JacksonXmlProperty(localName = "relation", namespace = META_MODEL_NAMESPACE)
    private List<Relation> relations;

    @JacksonXmlProperty(namespace = META_MODEL_NAMESPACE)
    private EntitiesGroup entitiesGroup;

    /**
     * {@inheritDoc}
     */
    @Override
    public String getInstanceId() {
        // Singleton per storage id
        return ModelUtils.DEFAULT_MODEL_INSTANCE_ID;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getTypeId() {
        return TypeIds.DATA_MODEL;
    }

    public EntitiesGroup getEntitiesGroup() {
        return entitiesGroup;
    }

    public void setEntitiesGroup(EntitiesGroup value) {
        this.entitiesGroup = value;
    }

    public List<LookupEntity> getLookupEntities() {
        if (lookupEntities == null) {
            lookupEntities = new ArrayList<>();
        }
        return lookupEntities;
    }

    public void setLookupEntities(List<LookupEntity> lookupEntities) {
        withLookupEntities(lookupEntities);
    }

    public List<NestedEntity> getNestedEntities() {
        if (nestedEntities == null) {
            nestedEntities = new ArrayList<>();
        }
        return nestedEntities;
    }

    public void setNestedEntities(List<NestedEntity> nestedEntities) {
        withNestedEntities(nestedEntities);
    }

    public List<Entity> getEntities() {
        if (entities == null) {
            entities = new ArrayList<>();
        }
        return entities;
    }

    public void setEntities(List<Entity> entities) {
        withEntities(entities);
    }

    public List<Relation> getRelations() {
        if (relations == null) {
            relations = new ArrayList<>();
        }
        return relations;
    }

    public void setRelations(List<Relation> relations) {
        withRelations(relations);
    }

    public DataModel withEntitiesGroup(EntitiesGroup value) {
        setEntitiesGroup(value);
        return this;
    }

    public DataModel withLookupEntities(LookupEntity... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            Collections.addAll(getLookupEntities(), values);
        }
        return this;
    }

    public DataModel withLookupEntities(Collection<LookupEntity> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getLookupEntities().addAll(values);
        }
        return this;
    }

    public DataModel withNestedEntities(NestedEntity... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            Collections.addAll(getNestedEntities(), values);
        }
        return this;
    }

    public DataModel withNestedEntities(Collection<NestedEntity> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getNestedEntities().addAll(values);
        }
        return this;
    }

    public DataModel withEntities(Entity... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            Collections.addAll(getEntities(), values);
        }
        return this;
    }

    public DataModel withEntities(Collection<Entity> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getEntities().addAll(values);
        }
        return this;
    }

    public DataModel withRelations(Relation... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            Collections.addAll(getRelations(), values);
        }
        return this;
    }

    public DataModel withRelations(Collection<Relation> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getRelations().addAll(values);
        }
        return this;
    }
}
